﻿using Microsoft.Extensions.Caching.Memory;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;

namespace PineLake.Drmwe.Caching.MemoryCache
{
    /// <summary>
    /// 内存缓存
    /// </summary>
    public class MemoryCaching : ICaching
    {
        //引用Microsoft.Extensions.Caching.Memory;这个和.net 还是不一样，没有了Httpruntime了
        private readonly IMemoryCache _Cache;
        public MemoryCaching(IMemoryCache ICache)
        {
            _Cache = ICache;
        }
        /// <summary>
        /// 缓存项是否存在
        /// </summary>
        /// <param name="Key">缓存的Key</param>
        /// <returns></returns>
        public bool Exists(string Key)
        {
            if (!string.IsNullOrEmpty(Key))
            {
                return _Cache.TryGetValue(Key, out _);
            }
            else
            {
                return false;
            }
        }
        /// <summary>
        /// 获取缓存
        /// </summary>
        /// <param name="Key">缓存Key</param>
        /// <returns></returns>
        public object Get(string Key)
        {
            if (!string.IsNullOrEmpty(Key))
            {
                return _Cache.Get(Key);
            }
            else
            {
                return "";
            }
        }
        /// <summary>
        /// 获取缓存
        /// </summary>
        /// <param name="Key">缓存Key</param>
        /// <returns></returns>
        public T Get<T>(string Key)
        {
            if (Key == null)
                throw new ArgumentNullException(nameof(Key));

            return _Cache.Get<T>(Key);
        }
        /// <summary>
        /// 获取所有缓存键
        /// </summary>
        /// <returns></returns>
        public List<string> GetCacheKeys()
        {
            const BindingFlags flags = BindingFlags.Instance | BindingFlags.NonPublic;
            var entries = _Cache.GetType().GetField("_entries", flags).GetValue(_Cache);
            var cacheItems = entries as IDictionary;
            var keys = new List<string>();
            if (cacheItems == null) return keys;
            foreach (DictionaryEntry cacheItem in cacheItems)
            {
                keys.Add(cacheItem.Key.ToString());
            }
            return keys;
        }

        /// <summary>
        /// 删除缓存
        /// </summary>
        /// <param name="Key">缓存Key</param>
        /// <returns></returns>
        public void Remove(string Key)
        {
            if (Key != null)
                _Cache.Remove(Key);
        }
        /// <summary>
        /// 批量删除缓存
        /// </summary>
        /// <param name="Keys">缓存Keys列表</param>
        public void RemoveAllByKeys(IEnumerable<string> Keys)
        {
            if (Keys != null)
            {
                Keys.ToList().ForEach(item => _Cache.Remove(item));
            }
        }
        /// <summary>
        /// 删除所有缓存
        /// </summary>
        public void RemoveCacheAll()
        {
            var l = GetCacheKeys();
            foreach (var s in l)
            {
                Remove(s);
            }
        }
        /// <summary>
        /// 添加(滑动过期)缓存
        /// </summary>
        /// <param name="Key">缓存Key</param>
        /// <param name="Value">缓存Value</param>
        /// <param name="ExpiresSliding">滑动过期时长（如果在过期时间内有操作，则以当前时间点延长过期时间</param>
        /// <param name="ExpiressAbsoulte">绝对过期时长</param>
        /// <returns></returns>
        public bool Set(string Key, object Value, TimeSpan ExpiresSliding, TimeSpan ExpiressAbsoulte)
        {
            if (!string.IsNullOrEmpty(Key) && Value != null)
            {
                _Cache.Set(Key, Value, new MemoryCacheEntryOptions().SetSlidingExpiration(ExpiresSliding).SetAbsoluteExpiration(ExpiressAbsoulte));
                return Exists(Key);
            }
            else
            {
                return false;
            }
        }
        /// <summary>
        /// 添加(滑动过期)缓存
        /// </summary>
        /// <param name="Key">缓存Key</param> 
        /// <param name="Value">缓存Value</param>
        /// <param name="ExpiresIn">缓存时长</param>
        /// <param name="IsSliding">是否滑动过期（如果在过期时间内有操作，则以当前时间点延长过期时间）</param>
        /// <returns></returns>
        public bool Set(string Key, object Value, TimeSpan ExpiresIn, bool IsSliding = false)
        {
            if (!string.IsNullOrEmpty(Key) && Value != null)
            {
                _Cache.Set(Key, Value, IsSliding ? new MemoryCacheEntryOptions().SetSlidingExpiration(ExpiresIn) : new MemoryCacheEntryOptions().SetAbsoluteExpiration(ExpiresIn));
                return Exists(Key);
            }
            else
            {
                return false;
            }
        }
        /// <summary>
        /// 添加缓存(默认缓存一天)
        /// </summary>
        /// <param name="Key">缓存Key</param>
        /// <param name="Value">缓存Value</param>
        /// <returns></returns>
        public void Set(string Key, object Value)
        {
            Set(Key, Value, TimeSpan.FromDays(1));
        }
        /// <summary>
        /// 添加(滑动过期)缓存
        /// </summary>
        /// <param name="Key">缓存Key</param> 
        /// <param name="Value">缓存Value</param>
        /// <param name="Ts">缓存时长</param>
        public void Set(string Key, object Value, TimeSpan Ts)
        {
            Set(Key, Value, Ts, false);
        }
        /// <summary>
        /// 添加缓存(多少秒后过期)
        /// </summary>
        /// <param name="Key">缓存Key</param>
        /// <param name="Value">缓存Value</param>
        /// <param name="seconds">过期时间(秒)</param>
        /// <returns></returns>
        public void Set(string Key, object Value, int seconds)
        {
            var ts = TimeSpan.FromSeconds(seconds);
            Set(Key, Value, ts, false);
        }
    }
}
